package Stack_04.calculate_03;
import Stack_04.BasedOnTheLinkedList_02.ObjectNode;
import Stack_04.BasedOnTheLinkedList_02.StackBasedOnTheLinkedList;
/*
 * @Author 罗
 * @date 2020/3/13 - 10:59 下午
 *
 */

public class Calculator {
    private StackForCalculator numStack;
    private StackForCalculator symbolStack;

    /**
     * 1.通过一个index的值（索引）来遍历表达式
     * 2.如果发现是一个数字，则直接放入数栈numStack
     * 3.如果扫描到的是一个符号，则分一下情况
     *      3.1 如果发现当前的符号栈为空，则直接入栈
     *      3.2 如果符号栈symbolStack有操作符，就进行比较
     *              (1)如果当前的操作符优先级小于或者等于栈中的操作符
     *              就需要从数栈numStack中pop出两个数字还有从符号栈symbolStack
     *                  中pop出一个符号，进行计算并得到结果，将结果存入数栈numStack
     *              然后将当前的操作符放入符号栈symbolStack
     *              (2)如果当前操作符的优先级大雨栈中的操作符，则直接入符号栈symbolStack
     * 4.当表达式扫描完毕，就顺序从符号栈和数栈中pop出相应的数字和符号，并运行
     * 5.最后在数栈只有一个数字，就是表达式的结果
     * @param expression
     */
    public void parse(String expression){
//        用于将多位数字拼接
        StringBuilder buildNumber = new StringBuilder();

        for (int i = 0; i < expression.length(); i++) {

            char temp = expression.charAt(i);

            if(StackForCalculator.isOperation(temp)){
/*              是运算符
                    1.将之前拼接好的数字，压入numStack
                    2.将StringBuilder中的字符串清空，以存放下一个数字
 */
                pushStringBuilderToNumStack(buildNumber);

                if(symbolStack.isEmpty()){
                    symbolStack.push(new ObjectNode(temp));
                }else{
                    int newSymbolPriority = StackForCalculator.priority(temp);
//                    将栈中的符号弹出，以用于比较
                    ObjectNode wasInSymbolStack = symbolStack.pop();

                    char wasInSymbolStackValue = wasInSymbolStack.getNode().toString().charAt(0);
                    int wasInSymbolStackPriority = StackForCalculator.priority(wasInSymbolStackValue);
                    if(newSymbolPriority <= wasInSymbolStackPriority){
/*                      新符号的优先级 <= 栈中符号的优先级
                            1.从numStack中弹出两个数字，和symbolStack中弹出一个符号(已经弹出)以用于计算
 */
                            int value1 = Integer.parseInt(numStack.pop().getNode().toString());
                            int value2 = Integer.parseInt(numStack.pop().getNode().toString());
                            double result = StackForCalculator.calculate(value1,value2,wasInSymbolStackValue);
//                          2.把计算结果压入数字栈
                            numStack.push(new ObjectNode(result));
//                          3.将当前操作符压入符号栈
                            symbolStack.push(new ObjectNode(temp));
                    } else{
//                         2.当前操作符的优先级大雨栈中的操作符，则直接入符号栈symbolStack
//                              (1) 把之前从 符号栈中取出来用于比较的 wasInSymbolStack 再放回符号栈
                                    symbolStack.push(wasInSymbolStack);
//                              (2) 把新符号放入符号栈
                                    symbolStack.push(new ObjectNode(temp));
                    }
                }
            }else{
                /*  如果在这里直接将获取到的单个数字直接 放入 numStack，那么放入的永远只是一位数
                 *      只能进行10以内的加减法
                 *  numStack.push(new ObjectNode(temp));
                 *  可以用字符串拼接，当检测到是符号的时候再把拼接好数字的数字push() -> numStack
                 * */
                buildNumber.append(temp);
            }
        }
/*      因为最后一位是数字，只有当是符号的时候，才能把StringBuffer中的字符串转为数字，所以表达式扫描完之后，还要手动的
            将未添加的数字添加到numStack中
            1.将之前拼接好的数字，压入numStack
            2.将StringBuilder中的字符串清空，以存放下一个数字
*/
        pushStringBuilderToNumStack(buildNumber);

        System.out.println("遍历numberStack");
        numStack.show();
        System.out.println("遍历symbolStack");
        symbolStack.show();
        while( ! symbolStack.isEmpty()) {
//        取出剩余的结果
            int value1 = Integer.parseInt(numStack.pop().getNode().toString());
            int value2 = Integer.parseInt(numStack.pop().getNode().toString());
            int symbol = symbolStack.pop().getNode().toString().charAt(0);
//        计算结果
            double result = StackForCalculator.calculate(value1, value2, symbol);
//        将结果继续压入numStack
            numStack.push(new ObjectNode(result));
        }
        System.out.println("结果："+numStack.pop().getNode());
    }

    /**
     * 将未添加的数字添加到numStack中
     *             1.将之前拼接好的数字，压入numStack
     *             2.将StringBuilder中的字符串清空，以存放下一个数字
     * @param buildNumber
     */
    private void pushStringBuilderToNumStack(StringBuilder buildNumber){

        if(! buildNumber.toString().contentEquals("")){

            numStack.push(new ObjectNode(buildNumber.toString()));
//                  2.将StringBuilder中的字符串清空，以存放下一个数字
            buildNumber.delete(0,buildNumber.length());
        }

    }

    public Calculator() {
        numStack = new StackForCalculator();
        symbolStack = new StackForCalculator();
    }
}
